/*
 * BitMapFreeSpaceManager.cpp
 *
 *  Created on: Nov 19, 2012
 *      Author: m
 */

#include "BitMapFreeSpaceManager.h"

namespace physical
{

BitMapFreeSpaceManager::BitMapFreeSpaceManager( size_t size ) :
    m_size( size ),
    m_bitmap( new byte[m_size] )
{
    memset( m_bitmap.get(), 0x00, m_size );
}

BitMapFreeSpaceManager::BitMapFreeSpaceManager( size_t size, const byte* value ) :
    m_size( size ),
    m_bitmap( new byte[m_size] )
{
    memcpy( m_bitmap.get(), value, m_size );
}

BitMapFreeSpaceManager::~BitMapFreeSpaceManager()
{
}

void BitMapFreeSpaceManager::free( blockNumber id )
{
    size_t byteOffset, bitOffset;
    //byte mask;

    byteOffset = id / 8;
    bitOffset = id % 8;

    this->unsetBit( bitOffset, byteOffset );
}

void BitMapFreeSpaceManager::unfree( blockNumber id )
{
    size_t byteOffset, bitOffset;

    byteOffset = id / 8;
    bitOffset = id % 8;

    this->setBit( bitOffset, byteOffset );
}

blockNumber BitMapFreeSpaceManager::getFreeBlockNumber() const
{
    long byteOffset = -1;
    blockNumber result = 0;

    // Busco el 1er byte con un bloque libre (o sea con un cero)
    for ( size_t i = 0; i < m_size; i++ )
    {
        if ( ~( m_bitmap[i] ) )
        {
            byteOffset = i;
            break;
        }
    }

    // si encontré alguno calculo el bit del bloque libre
    if ( byteOffset != -1 )
    {
        for ( int bitOffset = 0; bitOffset < 8; ++bitOffset )
        {
            if ( !this->testBit( bitOffset, byteOffset ) )
            {
                result = byteOffset * 8 + bitOffset;
                break;
            }
        }
    }
    else
        throw NoMoreFreeBlocksException();

    return result;
}

bool BitMapFreeSpaceManager::isFree( blockNumber id ) const
{
    size_t byteOffset;
    size_t bitOffset;

    byteOffset = id / 8;
    bitOffset = id % 8;

    return !this->testBit( bitOffset, byteOffset);
}

const byte* BitMapFreeSpaceManager::get() const
{
    return m_bitmap.get();
}

void BitMapFreeSpaceManager::set( const byte* newContent )
{
    memcpy( m_bitmap.get(), newContent, m_size );
}

size_t BitMapFreeSpaceManager::getSize() const
{
    return m_size;
}

} /* namespace physical */
